
#include "config.hpp"

#include "atr/iterator.hpp"

using namespace atr;

template <typename ... Types> 
struct TestList{};

TEST(IteratorTest, EmptyContainer)
{
    iterator<TestList<>, TestList<>> i;     UNUSED(i);
}

TEST(IteratorTest, NonEmptyContainer)
{
    iterator<TestList<int, long, char>, TestList<char, size_t>> i;   UNUSED(i);
}

TEST(IteratorTest, Next_OneElement)
{
    using A = iterator<TestList<>, TestList<int>>::begin;
    EXPECT_SAME( int, A::type );

    using E1 = iterator<TestList<int>, TestList<>>;
    using E2 = iterator<TestList<>, TestList<int>>::end;
    EXPECT_SAME( E1, A::next );
    EXPECT_SAME( E2, A::next );
}

TEST(IteratorTest, Next)
{
    using A = iterator<TestList<>, TestList<size_t, int, long, char>>::begin;
    EXPECT_SAME( size_t, A::type );

    using E2 = iterator<TestList<size_t>, TestList<int, long, char>>;
    using E3 = iterator<TestList<size_t, int>, TestList<long, char>>;
    using E4 = iterator<TestList<size_t, int, long>, TestList<char>>;
    using E5 = iterator<TestList<size_t, int, long, char>, TestList<>>;

    EXPECT_SAME( E2, A::next );
    EXPECT_SAME( E3, A::next::next );
    EXPECT_SAME( E4, A::next::next::next );
    EXPECT_SAME( E5, A::next::next::next::next );
    EXPECT_SAME( E5, A::end );
}

TEST(IteratorTest, Prev_OneElement)
{
    using A = iterator<TestList<int>, TestList<>>::prev;
    EXPECT_SAME( int, A::type );

    using E1 = iterator<TestList<>, TestList<int>>;
    using E2 = iterator<TestList<int>, TestList<>>;

    EXPECT_SAME( E1, A );
    EXPECT_SAME( E2, A::next );
}

TEST(IteratorTest, Prev)
{
    using A = iterator<TestList<size_t>, TestList<int, long, char>>::prev;
    EXPECT_SAME( size_t, A::type );

    using E2 = iterator<TestList<size_t, int, long>, TestList<char>>;
    using E3 = iterator<TestList<size_t, int>, TestList<long, char>>;
    using E4 = iterator<TestList<size_t>, TestList<int, long, char>>;
    using E5 = iterator<TestList<size_t, int, long, char>, TestList<>>;

    EXPECT_SAME( E2, A::end::prev );
    EXPECT_SAME( E3, A::end::prev::prev );
    EXPECT_SAME( E4, A::end::prev::prev::prev );
    EXPECT_SAME( E2, A::end::prev::next::prev );
    EXPECT_SAME( E5, A::end );
}
